home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Internet / Misc / ytalk / Source / term.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  14.2 KB  |  777 lines

  1. /* term.c - curses environment terminal functions for YTalk V2.0 */
  2.  
  3. /*               NOTICE
  4.  *
  5.  * Copyright (c) 1990 Britt Yenne.  All rights reserved.
  6.  * 
  7.  * This software is provided AS-IS.  The author gives no warranty,
  8.  * real or assumed, and takes no responsibility whatsoever for any 
  9.  * use or misuse of this software, or any damage created by its use
  10.  * or misuse.
  11.  * 
  12.  * This software may be freely copied and distributed provided that
  13.  * no part of this NOTICE is deleted or edited in any manner.
  14.  * 
  15.  */
  16.  
  17. /* Mail comments or questions to yenne@ccwf.cc.utexas.edu */
  18.  
  19. /* A valid terminal interface to YTalk implements these functions:
  20.  *
  21.  * init_term()        Initialize the terminal interface and create
  22.  *            the main console terminal for input.
  23.  *
  24.  * close_term()        Shut down the terminal system.
  25.  *
  26.  * add_window(title)    Add a new window, using the specified title.  This
  27.  *            function should return an integer window descriptor
  28.  *            which will remain constant for the life of this
  29.  *            particular window.  All subsequent calls which
  30.  *            process this window will be sent this window
  31.  *            descriptor.  Program main.c assumes that the main
  32.  *            window (input window) has a descriptor of zero.
  33.  *
  34.  * del_window(w)    Delete the window with descriptor w.
  35.  *
  36.  * redraw()        Redraw all windows.
  37.  *
  38.  * add_char(w, c)    Add the character c to window w.  Do NOT attempt
  39.  *            to translate the character to anything except
  40.  *            newlines and tabs.
  41.  *
  42.  * w_rub(w)        Destructively backspace one character in window w.
  43.  * w_kill(w)        Erase the current line in window w.
  44.  * w_word(w)        Erase one word in window w.
  45.  * w_clr(w)        Clear window w.
  46.  *
  47.  * showerror(str, e)    Display a user-friendly error message by outputting
  48.  *            the string str and displaying the system error
  49.  *            number e, if e is not zero.
  50.  *
  51.  * showmenu()        Display the main menu, and input the various fields
  52.  *            of the 'inptype' structure from the user.
  53.  *
  54.  * yes_no(str)        Display the string str, then read a yes/no response
  55.  *            from the user and return 'y' or 'n'.
  56.  */
  57.  
  58. #include "ytalk.h"
  59. #include <sys/time.h>
  60. #include <sys/types.h>
  61. #include <ctype.h>
  62. #include <curses.h>
  63. #include <stdio.h>
  64.  
  65. #define TLEN    20
  66.  
  67. typedef struct {
  68.     WINDOW *c_win;    /* curses window */
  69.     char name[TLEN];    /* name of window */
  70. } wind;
  71.  
  72. #define XPOS    c_win->_curx
  73. #define YPOS    c_win->_cury
  74. #define XMAX    c_win->_maxx
  75. #define YMAX    c_win->_maxy
  76.  
  77. wind win[MAXC];        /* curses window array */
  78. int wp[MAXC];        /* translates user window ID to array above */
  79. int scr = -1;        /* number of active screens */
  80. extern char edit[4];    /* for word wrap */
  81. extern inptype inp;
  82.  
  83. /* Initialize terminal
  84.  */
  85. int init_term()
  86. {
  87.     int i;
  88.  
  89.     if(scr >= 0)
  90.     close_term();
  91.     for(i = 0; i < MAXC; i++)
  92.     wp[i] = -1;
  93.     initscr();
  94.     noraw();
  95.     cmode();
  96.     noecho();
  97.     scr = 0;
  98.     if(add_window("YTalk Version 2.0") < 0)
  99.     {
  100.     close_term();
  101.     return -1;
  102.     }
  103.     return 0;
  104. }
  105.  
  106. /* Shut down terminal
  107.  */
  108. close_term()
  109. {
  110.     if(scr == -1)
  111.     return;
  112.     clear();
  113.     refresh();
  114.     endwin();
  115.     scr = -1;
  116. }
  117.  
  118. /* resize_win is an internal routine to resize a curses window and copy
  119.  * as much of the original window as possible into the new one.
  120.  */
  121. WINDOW *resize_win(c_win, len, width, sy, sx)
  122. WINDOW *c_win;
  123. int len, width, sy, sx;
  124. {
  125.     register int x, y, ny, my;
  126.     register char gotsp;
  127.     int oldx, oldy;
  128.     WINDOW *new;
  129.  
  130.     if((new = newwin(len, width, sy, sx)) == (WINDOW *)0)
  131.     {
  132.     panic("newwin");
  133.     yytalkabort(6);
  134.     }
  135.     wclear(new);
  136.     if(c_win != (WINDOW *)0)
  137.     {
  138.     oldx = XPOS;
  139.     oldy = YPOS;
  140.     my = (len<YMAX)?len:YMAX;
  141.     my -= 2;
  142.     y = oldy - my;
  143.     while(y < 0)
  144.         y += YMAX;
  145.     for(gotsp = 0, ny = 0; ny <= my; ny++, y++)
  146.     {
  147.         if(y >= YMAX)
  148.         y = 0;
  149.         for(x = 0; x < XMAX; x++)
  150.         {
  151.         wmove(c_win, y, x);
  152.         if(winch(c_win) != ' ')
  153.         {
  154.             gotsp = 1;
  155.             break;
  156.         }
  157.         }
  158.         if(gotsp)
  159.         break;
  160.     }
  161.     for(; ny <= my; ny++, y++)
  162.     {
  163.         if(y >= YMAX)
  164.         y = 0;
  165.         for(x = 0; x < width; x++)
  166.         {
  167.         if(ny == my && x >= oldx)
  168.             break;
  169.         if(x < XMAX)
  170.         {
  171.             wmove(c_win, y, x);
  172.             waddch(new, winch(c_win));
  173.         }
  174.         else
  175.         {
  176.             waddch(new, '\n');
  177.             break;
  178.         }
  179.         }
  180.     }
  181.     delwin(c_win);
  182.     if(new->_cury == (new->_maxy-1))
  183.     {
  184.         x = new->_curx;
  185.         y = new->_cury;
  186.         wmove(new, 0, 0);
  187.         wclrtoeol(new);
  188.         wmove(new, y, x);
  189.     }
  190.     }
  191.     return new;
  192. }
  193.  
  194. /* Add a new window and return a window descriptor.
  195.  */
  196. int add_window(title)
  197. char *title;
  198. {
  199.     int pt, n, y, r;
  200.  
  201.     if(scr < 0)
  202.     return -1;
  203.     for(pt = 0; pt < MAXC; pt++)
  204.     if(wp[pt] == -1)
  205.         break;
  206.     if(pt >= MAXC)
  207.     return -1;
  208.     wp[pt] = scr++;
  209.     n = LINES / scr;
  210.     if(n < 3)            /* always keep at least 3 lines per window */
  211.     return -1;
  212.  
  213.     strncpy(win[scr-1].name, title, TLEN);
  214.     win[scr-1].name[TLEN-1] = '\0';
  215.  
  216.     clear();
  217.     for(y = 0, r = 0; y < scr; y++, r += n)
  218.     {
  219.     if(y == (scr-1))
  220.     {
  221.         n = LINES - r;
  222.         win[y].c_win = (WINDOW *)0;
  223.     }
  224.     win[y].c_win = resize_win(win[y].c_win, n-1, COLS, r+1, 0);
  225.     barit(r, win[y].name);
  226.     wrefresh(win[y].c_win);
  227.     }
  228.     refresh();
  229.     return pt;
  230. }
  231.  
  232. /* Delete a window by window descriptor.
  233.  */
  234. int del_window(pt)
  235. {
  236.     int n, y, r, w;
  237.  
  238.     if(pt < 0 || pt >= MAXC || scr == 1)
  239.     return -1;
  240.     if(wp[pt] == -1)
  241.     return -1;
  242.  
  243.     w = wp[pt];
  244.     delwin(win[w].c_win);
  245.  
  246.     scr--;
  247.     for(y = w; y < scr; y++)
  248.     win[y] = win[y+1];
  249.     for(y = 0; y < MAXC; y++)
  250.     if(wp[y] > w)
  251.         wp[y]--;
  252.     wp[pt] == -1;
  253.     n = LINES / scr;
  254.  
  255.     clear();
  256.     for(y = 0, r = 0; y < scr; y++, r += n)
  257.     {
  258.     if(y == (scr-1))
  259.         n = LINES - r;
  260.     win[y].c_win = resize_win(win[y].c_win, n-1, COLS, r+1, 0);
  261.     barit(r, win[y].name);
  262.     wrefresh(win[y].c_win);
  263.     }
  264.     refresh();
  265.     return 0;
  266. }
  267.  
  268. /* Delete a temporary window by window pointer.
  269.  */
  270. void kill_window(w)
  271. WINDOW *w;
  272. {
  273.     int y;
  274.  
  275.     if(w != (WINDOW *)0)
  276.     delwin(w);
  277.     refresh();
  278.     for(y = 0; y < scr; y++)
  279.     wrefresh(win[y].c_win);
  280. }
  281.  
  282. /* barit() is an internal routine to display a title bar across the screen
  283.  * for each window.
  284.  */
  285. barit(r, t)
  286. char *t;
  287. {
  288.     int x, c;
  289.  
  290.     x = (COLS/2) - (strlen(t)/2) - 2;
  291.     move(r, 0);
  292.     c = 0;
  293.     if(x > 1)
  294.     {
  295.     for(; c < x; c++)
  296.         addch('-');
  297.     printw("= %s =", t);
  298.     c += strlen(t) + 4;
  299.     }
  300.     for(; c < COLS; c++)
  301.     addch('-');
  302.     refresh();
  303. }
  304.  
  305. /* Erase and redraw the entire screen.
  306.  */
  307. int redraw()
  308. {
  309.     int y;
  310.  
  311.     if(scr < 0)
  312.     return -1;
  313. /*     touchwin(stdscr); */
  314.     clearok(stdscr, TRUE);
  315.     refresh();
  316.     for(y = 0; y < scr; y++)
  317.     {
  318.     touchwin(win[y].c_win);
  319.     wrefresh(win[y].c_win);
  320.     }
  321.     return 0;
  322. }
  323.  
  324. /* newline() is an internal routine to process a newline.
  325.  */
  326. newline(c_win)
  327. WINDOW *c_win;
  328. {
  329.     int y;
  330.  
  331.     y = YPOS;
  332.     if(++y >= YMAX)
  333.     {
  334.     y = 0;
  335.     wmove(c_win, 0, 0);
  336.     }
  337.     else
  338.     waddch(c_win, '\n');
  339.     clrnxtline(c_win);
  340. }
  341.  
  342. /* clrnxtline() is an internal routine to clear the next available line
  343.  * in a given curses window.
  344.  */
  345. clrnxtline(c_win)
  346. WINDOW *c_win;
  347. {
  348.     int y, sx, sy;
  349.  
  350.     sx = XPOS;
  351.     y = sy = YPOS;
  352.     if(++y >= YMAX)
  353.     y = 0;
  354.     wmove(c_win, y, 0);
  355.     wclrtoeol(c_win);
  356.     wmove(c_win, sy, sx);
  357. }
  358.  
  359. /* Add a character to a window.
  360.  */
  361. add_char(w, ch)
  362. char ch;
  363. {
  364.     register int x, y, i;
  365.  
  366.     if(w < 0 || w >= MAXC)
  367.     return -1;
  368.     if((w = wp[w]) == -1)
  369.     return -1;
  370.  
  371. /* MOD for auto word wrap - BSY 02/13/91 */
  372.     if(w == 0 && ch != '\t' && ch != '\n' && COLS > 40)
  373.     {
  374.     if(win[w].XPOS + ((ch<32)?2:1) >= COLS)
  375.     {
  376.         char saveit[30], *s;
  377.  
  378.         if(ch == ' ')
  379.         {
  380.         xmit_char('\n');
  381.         return -1;
  382.         }
  383.         x = win[w].XPOS;
  384.         y = win[w].YPOS;
  385.         for(s = saveit; x - win[w].XPOS < 20; s++)
  386.         {
  387.         wmove(win[w].c_win, y, win[w].XPOS-1);
  388.         if((*s = winch(win[w].c_win)) == ' ')
  389.             break;
  390.         }
  391.         wmove(win[w].c_win, y, x);
  392.         if(s == saveit)
  393.         xmit_char('\n');
  394.         else if(*s == ' ')
  395.         {
  396.                 for (i=s-saveit;i>0;i--) xmit_char(RUB);
  397. //        xmit_char(WORD);
  398.         xmit_char('\n');
  399.         for(s--; s >= saveit; s--)
  400.             xmit_char(*s);
  401.         }
  402.     }
  403.     }
  404. /* end of MOD for auto word wrap */
  405.  
  406.     wadd_char(win[w].c_win, ch);
  407.     return 0;
  408. }
  409.  
  410. /* wadd_char is an internal routine to add a character to a window.
  411.  */
  412. wadd_char(c_win, ch)
  413. WINDOW *c_win;
  414. char ch;
  415. {
  416.     if(ch == '\n')
  417.     newline(c_win);
  418.     else if(ch == '\t')
  419.     waddch(c_win, ch);
  420.     else if(ch < 32)
  421.     {
  422.     wadd_char(c_win, '^');
  423.     wadd_char(c_win, ch+64);
  424.     return;
  425.     }
  426.     else if(ch < 127)
  427.     {
  428.     if(XPOS+1 >= COLS)
  429.         newline(c_win);
  430.     waddch(c_win, ch);
  431.     }
  432.     wrefresh(c_win);
  433. }
  434.  
  435. /* Process a rubout in a window.
  436.  */
  437. w_rub(w)
  438. {
  439.     if(w < 0 || w >= MAXC)
  440.     return;
  441.     if((w = wp[w]) == -1)
  442.     return;
  443.     if(win[w].XPOS == 0)
  444.     return;
  445.     waddch(win[w].c_win, '\010');
  446.     waddch(win[w].c_win, ' ');
  447.     waddch(win[w].c_win, '\010');
  448.     wrefresh(win[w].c_win);
  449. }
  450.  
  451. /* Kill the current line in a window.
  452.  */
  453. w_kill(w)
  454. {
  455.     if(w < 0 || w >= MAXC)
  456.     return;
  457.     if((w = wp[w]) == -1)
  458.     return;
  459.     if(win[w].XPOS == 0)
  460.     return;
  461.     wmove(win[w].c_win, win[w].YPOS, 0);
  462.     wclrtoeol(win[w].c_win);
  463.     wrefresh(win[w].c_win);
  464. }
  465.  
  466. /* Erase a word in a window.
  467.  */
  468. w_word(w)
  469. {
  470.     register char *c;
  471.  
  472.     if(w < 0 || w >= MAXC)
  473.     return;
  474.     if((w = wp[w]) == -1)
  475.     return;
  476.     if(win[w].XPOS == 0)
  477.     return;
  478.     do
  479.     {
  480.     waddch(win[w].c_win, '\010');
  481.     } while(win[w].XPOS > 0 && winch(win[w].c_win) == ' ');
  482.     do
  483.     {
  484.     waddch(win[w].c_win, '\010');
  485.     } while(win[w].XPOS > 0 && winch(win[w].c_win) != ' ');
  486.     if(win[w].XPOS > 0)
  487.     wmove(win[w].c_win, win[w].YPOS, win[w].XPOS+1);
  488.     wclrtoeol(win[w].c_win);
  489.     wrefresh(win[w].c_win);
  490. }
  491.  
  492. /* Clear a window.
  493.  */
  494. w_clr(w)
  495. {
  496.     int i;
  497.  
  498.     if(w < 0 || w >= MAXC)
  499.     return;
  500.     if((w = wp[w]) == -1)
  501.     return;
  502.     wclear(win[w].c_win);
  503.     wrefresh(win[w].c_win);
  504. }
  505.  
  506. /* Display a user-friendly error message.
  507.  */
  508. showerror(str, e)
  509. char *str;
  510. {
  511.     int n, x, y, w = 66;
  512.     extern char *sys_errlist[];
  513.     WINDOW *new;
  514.  
  515.     if(scr < 0)
  516.         return -1;
  517.     if((x = (COLS / 2) - (w / 2)) <= 0)
  518.     {
  519.     x = 0;
  520.     w = COLS;
  521.     }
  522.     if((y = (LINES / 2) - 3) < 0)
  523.     y = 0;
  524.     if((new = newwin(6, w, y, x)) == (WINDOW *)0)
  525.     return -1;
  526.  
  527.     wmove(new, 1, 0);
  528.     if(str != NULL)
  529.     if(*str != '\0');
  530.         wprintw(new, "  YTalk error:  %s\n", str);
  531.     if(e != 0)
  532.     wprintw(new, "  System error: %s\n", sys_errlist[e]);
  533.     wmove(new, 4, 0);
  534.     wprintw(new, "  Press ESC to continue: ");
  535.  
  536.     x = new->_curx;
  537.     y = new->_cury;
  538.     box(new, '#', '#');
  539.  
  540.     wmove(new, y, x);
  541.     wrefresh(new);
  542.     putc('\07', stderr);
  543.     while(getch() != 27)
  544.     continue;
  545.     for(y = 0; y < scr; y++)
  546.     wtouch(new, win[y].c_win);
  547.     wtouch(new, stdscr);
  548.     kill_window(new);
  549.     return 0;
  550. }
  551.  
  552. /* Display the main menu.
  553.  */
  554. showmenu()
  555. {
  556.     int n, x, y, w = 50, l = 6, sel;
  557.     static int out;
  558.     struct timeval tv;
  559.     WINDOW *new = (WINDOW *)0;
  560.  
  561.     if(scr < 0)
  562.         return -1;
  563.     new = (WINDOW *)0;
  564.     out = 0;
  565.     tv.tv_sec = 0L;
  566.     tv.tv_usec = 500000L;
  567.     sel = 1<<0;
  568.     if(select(32, &sel, 0, 0, &tv) == 0)
  569.     {
  570.     if((x = (COLS / 2) - (w / 2)) <= 0)
  571.     {
  572.         x = 0;
  573.         w = COLS;
  574.     }
  575.     if((y = (LINES / 2) - (l / 2)) < 0)
  576.     {
  577.         y = 0;
  578.         l = LINES;
  579.     }
  580.     if((new = newwin(l, w, y, x)) == (WINDOW *)0)
  581.     {
  582.         panic("Cannot create a new window");
  583.         return -1;
  584.     }
  585.     wmove(new, 1, 0);
  586.     wprintw(new, "  a) Add a new user to session\n");
  587.     wprintw(new, "  d) Delete a user from session\n");
  588.     wprintw(new, "  o) Output a user to a file\n");
  589.     wmove(new, l-2, 0);
  590.     wprintw(new, "  Your choice: ");
  591.     x = new->_curx;
  592.     y = new->_cury;
  593.     box(new, '#', '#');
  594.     wmove(new, y, x);
  595.     wrefresh(new);
  596.     }
  597.     switch(inp.code = getch())
  598.     {
  599.     case 'a':    /* Add a user */
  600.         out = getusername("Add", NULL);
  601.         break;
  602.     case 'd':
  603.         out = getusername("Delete", NULL);
  604.         break;
  605.     case 'o':
  606.         out = getusername("Output", "Filename");
  607.         break;
  608.     default:
  609.         putc('\07', stderr);
  610.         out = -1;
  611.     }
  612.     if(new != (WINDOW *)0)
  613.     {
  614.     for(y = 0; y < scr; y++)
  615.         wtouch(new, win[y].c_win);
  616.     wtouch(new, stdscr);
  617.     kill_window(new);
  618.     }
  619.     return out;
  620. }
  621.  
  622. /* Internal routine to input a user name.
  623.  */
  624. getusername(str, prompt)
  625. char *str, *prompt;
  626. {
  627.     int x, y, w = 70, l = 3;
  628.     WINDOW *new;
  629.  
  630.     if(scr < 0)
  631.         return -1;
  632.     if(prompt != NULL)
  633.     l++;
  634.     if((x = (COLS / 2) - (w / 2)) <= 0)
  635.     {
  636.     x = 0;
  637.     w = COLS;
  638.     }
  639.     if((y = (LINES / 2) - (l / 2)) < 0)
  640.     {
  641.     y = 0;
  642.     l = LINES;
  643.     }
  644.     if((new = newwin(l, w, y, x)) == (WINDOW *)0)
  645.     {
  646.     panic("Cannot create a new window");
  647.     return -1;
  648.     }
  649.  
  650.     wmove(new, 1, 0);
  651.     wprintw(new, "  %s which user? ", str);
  652.     x = new->_curx;
  653.     y = new->_cury;
  654.     box(new, '#', '#');
  655.     wmove(new, y, x);
  656.     wrefresh(new);
  657.  
  658.     in_str(new, inp.name, w-x-1);
  659.  
  660.     if(inp.name[0] != '\0' && prompt != NULL)
  661.     {
  662.     wmove(new, 2, 2);
  663.     wprintw(new, "%s? ", prompt);
  664.     x = new->_curx;
  665.     y = new->_cury;
  666.     wrefresh(new);
  667.     in_str(new, inp.data, w-x-1);
  668.     }
  669.  
  670.     delwin(new);
  671.     for(y = 0; y < scr; y++)
  672.     wtouch(new, win[y].c_win);
  673.     wtouch(new, stdscr);
  674.     if(inp.name[0] == '\0')
  675.     return -1;
  676.     return 0;
  677. }
  678.  
  679. /* Internal routine to read a string from a curses window.
  680.  */
  681. in_str(c_win, str, max)
  682. WINDOW *c_win;
  683. char *str;
  684. {
  685.     int n;
  686.     char *c;
  687.  
  688.     for(c = str, n = 0; n < max;)
  689.     {
  690.     *c = getch();
  691.     if(*c == '\n')
  692.         break;
  693.     if(n > 0 && (*c == 8 || *c == 127))
  694.     {
  695.         c--;
  696.         n--;
  697.         waddch(c_win, 8);
  698.         waddch(c_win, ' ');
  699.         waddch(c_win, 8);
  700.         wrefresh(c_win);
  701.         continue;
  702.     }
  703.     if(*c < 32 || *c > 126 || n >= max-1)
  704.     {
  705.         putc('\07', stderr);
  706.         continue;
  707.     }
  708.     waddch(c_win, *c);
  709.     wrefresh(c_win);
  710.     n++;
  711.     c++;
  712.     }
  713.     *c = '\0';
  714. }
  715.  
  716. /* Display a prompt and read a yes/no response from user.
  717.  */
  718. char yes_no(str)
  719. char *str;
  720. {
  721.     int n, x, y, w = 60, l = 3, sel;
  722.     struct timeval tv;
  723.     static char ch;
  724.     WINDOW *new;
  725.  
  726.     if(scr < 0)
  727.         return -1;
  728.     new = (WINDOW *)0;
  729.     if((x = (COLS / 2) - (w / 2)) <= 0)
  730.     {
  731.     x = 0;
  732.     w = COLS;
  733.     }
  734.     if((y = (LINES / 2) - (l / 2)) < 0)
  735.     {
  736.     y = 0;
  737.     l = LINES;
  738.     }
  739.     if((new = newwin(l, w, y, x)) == (WINDOW *)0)
  740.     {
  741.     panic("Cannot create a new window");
  742.     return -1;
  743.     }
  744.  
  745.     wmove(new, 1, 0);
  746.     wprintw(new, "  %s ", str);
  747.     x = new->_curx;
  748.     y = new->_cury;
  749.     box(new, '#', '#');
  750.     wmove(new, y, x);
  751.     wrefresh(new);
  752.  
  753.     tv.tv_sec = 0L;
  754.     tv.tv_usec = 200000L;
  755.     sel = 1<<0;
  756.     while(select(32, &sel, 0, 0, &tv) == 1)
  757.     {
  758.     tv.tv_sec = 0L;
  759.     tv.tv_usec = 200000L;
  760.     sel = 1<<0;
  761.     getch();
  762.     }
  763.  
  764.     do
  765.     {
  766.     ch = getch();
  767.     if(isupper(ch))
  768.         ch -= 32;
  769.     } while(ch != 'y' && ch != 'n');
  770.  
  771.     for(y = 0; y < scr; y++)
  772.     wtouch(new, win[y].c_win);
  773.     wtouch(new, stdscr);
  774.     kill_window(new);
  775.     return ch;
  776. }
  777.